home *** CD-ROM | disk | FTP | other *** search
- /*----------------------------------------------------------------------------
-
- full.c
-
- This module handles tasks involving the full group list.
-
- Copyright © 1994-1995, Northwestern University.
-
- ----------------------------------------------------------------------------*/
-
- #include <string.h>
- #include <stdio.h>
-
- #include "glob.h"
- #include "full.h"
- #include "qsort.h"
- #include "dialog.h"
- #include "news.h"
- #include "newswatcher.h"
- #include "menus.h"
- #include "status.h"
- #include "wind.h"
- #include "group.h"
- #include "text.h"
- #include "memutil.h"
- #include "strutil.h"
- #include "windutil.h"
- #include "subscribe.h"
- #include "listutil.h"
- #include "fileutil.h"
-
-
-
- #define kMustCloseBeforeRebuildDlg 150
-
-
-
- static Handle gSortGroupNames;
-
-
-
- /*----------------------------------------------------------------------------
- FindGroupIndex
-
- Find the index of a group in the full group array gFullGroupArray.
-
- Entry: name = group name.
- gFullGroupArray sorted in increasing order by group name.
-
- Exit: function result = index in gFullGroupArray of group, or -1 if not found.
- ----------------------------------------------------------------------------*/
-
- short FindGroupIndex (char *name)
- {
- long low = 0;
- long high = gNumGroups-1;
- long mid;
- short compare;
-
- while (low <= high) {
- mid = (low + high) >> 1;
- compare = strcmp(name, *gGroupNames + (*gFullGroupArray)[mid].nameOffset);
- if (compare == 0) {
- return mid;
- } else if (compare < 0) {
- high = mid-1;
- } else {
- low = mid+1;
- }
- }
- return -1;
- }
-
-
-
- /*----------------------------------------------------------------------------
- GroupCompare
-
- The group comparison routine used in the calls to FastQSort in
- SortFullGroupArray and CheckForNewGroups below. It does a
- simple string compare and gives time to background applications.
-
- Entry: p = pointer to first group info struct.
- q = pointer to second group info struct.
- gSortGroupNames = handle to group names block.
-
- Exit: function result = error code.
- *result
- < 0 if first group name < second group name.
- = 0 if first group name = second group name.
- > 0 if first group name > second group name.
- ----------------------------------------------------------------------------*/
-
- static OSErr GroupCompare (TGroup *p, TGroup *q, short *result)
- {
- OSErr err;
- static short counter = 0;
-
- if ((++counter & 0x1f) == 0) {
- err = GiveTime(false);
- if (err != noErr) return err;
- counter = 0;
- }
-
- *result = strcmp(*gSortGroupNames + p->nameOffset,
- *gSortGroupNames + q->nameOffset);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- SortFullGroupArray
-
- Sort a full group array alphabetically by group name.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr SortFullGroupArray (TGroup **groupArray, short numGroups, Handle groupNames)
- {
- OSErr err = noErr;
- char state;
-
- if (numGroups > 0) {
- err = DisplayStatusMessageNumber(kStrSortingStatusMsg);
- if (err != noErr) return err;
- gSortGroupNames = groupNames;
- state = MyHGetState(groupArray);
- MyHLock(groupArray);
- err = FastQSort(*groupArray, numGroups, sizeof(TGroup),
- (SortCmpFunction)GroupCompare);
- MyHSetState(groupArray, state);
- if (err != noErr) return err;
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- InitializeGroupRecord
-
- Initialize a new group record.
-
- Entry: x = pointer to group record.
- offset = offset in gGroupNames of group name.
- ----------------------------------------------------------------------------*/
-
- static void InitializeGroupRecord (TGroup *x, long offset)
- {
- x->nameOffset = offset;
- x->firstMess = x->lastMess = 0;
- x->numUnread = 0;
- x->status = ' ';
- x->unread = nil;
- x->onlyRedrawCount = false;
- }
-
-
-
- /*----------------------------------------------------------------------------
- ReadGroupsFromPrefs
-
- Read the full group list stored on the preferences file.
-
- Entry: fSpec = pointer to file spec of prefs file.
- prefsInDataFork = true if prefs are in data fork of prefs file
- and the full group list follows the prefs. False if the
- prefs are in the resource fork and the data fork contains
- only the full group list.
- prefsVersion = version number of prefs file.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr ReadGroupsFromPrefs (FSSpec *fSpec, Boolean prefsInDataFork,
- unsigned long prefsVersion)
- {
- OSErr err = noErr;
- short fRefNum = 0, i;
- Boolean needSort = false;
- char *p, *pEnd;
- char *prevName = nil;
- char *curName;
- TGroup *x;
- long groupNamesSize;
- char state;
-
- err = DisplayStatusMessageNumber(kStrReadingStatusMsg);
- if (err != noErr) goto exit;
-
- err = FSpOpenDF(fSpec, fsRdPerm, &fRefNum);
- if (err != noErr) return noErr;
-
- /* Read the saved group names. */
-
- err = GetEOF(fRefNum, &groupNamesSize);
- if (err != noErr) goto exit;
- if (prefsInDataFork) {
- groupNamesSize -= sizeof(TPrefRec);
- if (groupNamesSize < 0) goto exit;
- err = SetFPos(fRefNum, fsFromStart, sizeof(TPrefRec));
- if (err != noErr) goto exit;
- }
- err = MyNewHandle(groupNamesSize, &gGroupNames);
- if (err != noErr) goto exit;
- state = MyHGetState(gGroupNames);
- MyHLock(gGroupNames);
- err = FSRead(fRefNum, &groupNamesSize, *gGroupNames);
- MyHSetState(gGroupNames, state);
- if (err != noErr) goto exit;
- MyFSClose(fRefNum, nil);
- fRefNum = 0;
-
- /* Special case the Cornell version 2.0d15-CU, which put
- a 32 byte authorization username and 32 bytes of zero at
- the end of the NU 2.0d14 prefs, which in any NU version
- of NW shows up as the first 64 bytes of what we think
- is the full group list! (Yes, yuck).
-
- First we check prefsVersion to see if it is 2.0d14. If
- it is, we then check byte 32 of the full group list. If
- byte 32 is 0, we assume this is a Cornell prefs file. In
- this case, we copy the first 32 bytes (the Cornell authorization
- username) to gPrefs.authUsername (our authorization username).
- We discard the next unused 32 zero bytes.
-
- Note that in NU prefs files, a 0 byte never appears in the
- full group list, so theoretically there is no chance of
- confusing an NU prefs file with a CU prefs file.
-
- This makes NU NewsWatcher 2.0d27 and later understand and
- properly convert 2.0d15-CU prefs files. The reverse will never
- work - 2.0d15-CU is not able to make any sense of any NU version
- prefs file.
- */
-
- if (prefsVersion == 0x02002014 && groupNamesSize >= 64 &&
- *(*gGroupNames+32) == 0)
- {
- BlockMoveData(*gGroupNames, gPrefs.authUsername, 32);
- groupNamesSize -= 64;
- BlockMoveData(*gGroupNames + 64, *gGroupNames, groupNamesSize);
- MySetHandleSize(gGroupNames, groupNamesSize);
- gFullGroupListDirty = true;
- }
-
- /* Check to make certain the last group name ends in CR. If not, strip
- any trailing junk. */
-
- p = *gGroupNames + groupNamesSize - 1;
- while (p >= *gGroupNames && *p != CR) p--;
- p++;
- if (p < *gGroupNames + groupNamesSize) {
- groupNamesSize = p - *gGroupNames;
- MySetHandleSize(gGroupNames, groupNamesSize);
- gFullGroupListDirty = true;
- if (p == *gGroupNames) return noErr;
- }
-
- /* Walk through the gGroupNames buffer. Count the number of groups.
- Change all CR to 0. Check to see if the groups are already sorted
- (they should be). */
-
- p = *gGroupNames;
- pEnd = p + groupNamesSize;
- gNumGroups = 0;
- while (p < pEnd && gNumGroups < 16000) {
- curName = p;
- while (*p != CR) p++;
- *p++ = 0;
- gNumGroups++;
- needSort = needSort || (prevName != nil && strcmp(prevName, curName) > 0);
- prevName = curName;
- }
-
- if (p < pEnd) {
- groupNamesSize = p - *gGroupNames;
- MySetHandleSize(gGroupNames, groupNamesSize);
- gFullGroupListDirty = true;
- ErrorMessageNumber(kStrTooManyPrefsFileGroups);
- }
-
- /* Allocate and initialize the full group array. */
-
- err = MyNewHandle(gNumGroups*sizeof(TGroup), &gFullGroupArray);
- if (err != noErr) goto exit;
-
- for (i = 0, x = *gFullGroupArray, p = *gGroupNames; i < gNumGroups; i++, x++) {
- InitializeGroupRecord(x, p - *gGroupNames);
- p += strlen(p) + 1;
- }
-
- /* If necessary, sort the full group array. */
-
- if (needSort) {
- gFullGroupListDirty = true;
- err = SortFullGroupArray(gFullGroupArray, gNumGroups, gGroupNames);
- if (err != noErr) goto exit;
- }
-
- return noErr;
-
- exit:
-
- MyDisposeHandle(gGroupNames);
- if (fRefNum != 0) MyFSClose(fRefNum, nil);
- gNumGroups = 0;
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- AdjustFullGroupListChildWindows
-
- This function must be called whenever the full group list changes. It locates
- all the open child subject list windows. If a group has been deleted, any
- associated open child subject list window is closed. If a group still exists,
- the "parentGroup" backpointer in the child window's TWindow info is adjusted
- to point to the new location of the parent group in the full group array
- gFullGroupArray.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr AdjustFullGroupListChildWindows (void)
- {
- TWindow **info, **childInfo;
- TChild **childList, **prevChildList;
- WindowPtr childWindow;
- CStr255 groupName;
- short index;
- OSErr err = noErr;
-
- gFullGroupListDirty = true;
- if (gFullGroupWindow == nil) return noErr;
- info = (TWindow**)GetWRefCon(gFullGroupWindow);
- childList = (**info).childList;
- prevChildList = nil;
- while (childList != nil) {
- childWindow = (**childList).childWindow;
- childInfo = (TWindow**)GetWRefCon(childWindow);
- strcpy(groupName, *gGroupNames + (**childInfo).groupNameOffset);
- index = FindGroupIndex(groupName);
- if (index == -1) {
- /* Group has been deleted. Close the child window. */
- err = DoClose(childWindow);
- if (err != noErr) return err;
- if (prevChildList == nil) {
- childList = (**info).childList;
- } else {
- childList = (**prevChildList).next;
- }
- } else {
- /* Group still exists. Update the parentGroup backpointer. */
- (**childInfo).parentGroup = index;
- prevChildList = childList;
- childList = (**childList).next;
- }
- }
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- UpdateFullGroupWindow
-
- Make sure that the Full Group List window corresponds to the changed
- full group list. It must be called whenever the full group list changes.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr UpdateFullGroupWindow (void)
- {
- TWindow **info;
- Point thePt;
- GrafPtr port;
- OSErr err = noErr;
-
- GetPort(&port);
-
- err = AdjustFullGroupListChildWindows();
- if (err != noErr) return err;
- if (gFullGroupWindow != nil) {
- info = (TWindow**)GetWRefCon(gFullGroupWindow);
- (**info).groupArray = gFullGroupArray;
- (**info).numGroups = gNumGroups;
- err = MakeGroupList(gNumGroups, (**info).theList);
- if (err != noErr) return err;
- SetPt(&thePt, 0, 0);
- MyLSetSelect(true, thePt, (**info).theList);
- SetPort(gFullGroupWindow);
- InvalRect(&gFullGroupWindow->portRect);
- }
-
- SetPort(port);
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MergeNewGroupsIntoFullGroupList
-
- Merge new groups into the full group list. Both lists must be sorted on
- entry. The full group list remains sorted on exit.
-
- Entry: newGroupsArray = handle to new groups array.
- numNew = number of new groups.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MergeNewGroupsIntoFullGroupList (TGroup **newGroupsArray, short numNew)
- {
- short numLeftToInsert, numToMoveUp;
- TGroup *fullListPtr, *newListPtr;
- char *newName;
- OSErr err = noErr;
-
- gNumGroups += numNew;
- err = MySetHandleSize(gFullGroupArray, gNumGroups*sizeof(TGroup));
- if (err != noErr) return err;
-
- numLeftToInsert = numNew;
- fullListPtr = *gFullGroupArray + gNumGroups - numNew - 1;
- newListPtr = *newGroupsArray + numNew - 1;
- while (numLeftToInsert > 0) {
- newName = *gGroupNames + newListPtr->nameOffset;
- numToMoveUp = 0;
- while (fullListPtr >= *gFullGroupArray &&
- strcmp(newName, *gGroupNames + fullListPtr->nameOffset) <= 0)
- {
- fullListPtr--;
- numToMoveUp++;
- }
- if (numToMoveUp > 0)
- BlockMoveData(fullListPtr + 1, fullListPtr + numLeftToInsert + 1,
- numToMoveUp*sizeof(TGroup));
- BlockMoveData(newListPtr, fullListPtr + numLeftToInsert, sizeof(TGroup));
- newListPtr--;
- numLeftToInsert--;
- }
-
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- CheckForNewGroups
-
- Check for any new groups created since last time we checked.
-
- Exit: function result = error code.
- *newGroupsArray = handle to group array, or nil if numNewGroups == 0.
- *numNewGroups = number of groups in group array.
- ----------------------------------------------------------------------------*/
-
- OSErr CheckForNewGroups (TGroup ***newGroupsArray, short *numNewGroups)
- {
- OSErr err = noErr;
- short len, nameWidth;
- long numGroups, numNew, i;
- Handle strings = nil;
- char *p, *q;
- long offset, savedGroupNamesSize;
- TGroup **groupArray = nil;
- TGroup *x;
- CStr255 groupName;
- GrafPtr port;
- char state;
- WindowPtr wind;
- TWindow **info;
- Handle unsubscribed;
-
- GetPort(&port);
- savedGroupNamesSize = GetHandleSize(gGroupNames);
-
- err = DisplayStatusMessageNumber(kStrCheckingNewStatusMsg);
- if (err != noErr) goto exit;
-
- /* Get the new group names from the server. */
-
- err = GetGroupNames(gPrefs.groupCheckTime, &strings, &numGroups);
- if (err != noErr) goto exit;
-
- /* Check for duplicates. Filter out the groups which are already present in
- the full group list. Check for too many new groups. */
-
- numNew = 0;
- for (i = 0, p = *strings, q = *strings; i < numGroups; i++) {
- len = strlen(q);
- if (FindGroupIndex(q) == -1) {
- if (gNumGroups + numNew >= 16000) break;
- strcpy(p, q);
- p += len+1;
- numNew++;
- }
- q += len+1;
- }
-
- MySetHandleSize(strings, p - *strings);
-
- if (i < numGroups) ErrorMessageNumber(kStrTooManyGroupsOnServer);
-
- if (numNew == 0) {
- MyDisposeHandle(strings);
- *numNewGroups = 0;
- *newGroupsArray = nil;
- GetDateTime(&gPrefs.groupCheckTime);
- SetPort(port);
- return noErr;
- }
-
- /* Append the new group names to the end of gGroupNames. */
-
- offset = savedGroupNamesSize;
- err = MyHandAndHand(strings, gGroupNames);
- if (err != noErr) goto exit;
-
- /* Allocate and initialize the group array for the new groups. */
-
- err = MyNewHandle(numNew * sizeof(TGroup), &groupArray);
- if (err != noErr) goto exit;
-
- for (i = 0, x = *groupArray, p = *gGroupNames + offset; i < numNew; i++, x++) {
- InitializeGroupRecord(x, p - *gGroupNames);
- p += strlen(p) + 1;
- }
-
- /* Sort the new groups array. */
-
- gSortGroupNames = gGroupNames;
- state = MyHGetState(groupArray);
- MyHLock(groupArray);
- err = FastQSort(*groupArray, numNew, sizeof(TGroup),
- (SortCmpFunction)GroupCompare);
- MyHSetState(groupArray, state);
- if (err != noErr) goto exit;
-
- /* Merge the new groups into the full group list. */
-
- err = MergeNewGroupsIntoFullGroupList(groupArray, numNew);
- if (err != noErr) goto exit;
-
- err = UpdateFullGroupWindow();
- if (err != noErr) goto exit;
-
- /* Update the last new groups check date and time. */
-
- GetDateTime(&gPrefs.groupCheckTime);
-
- /* Check to see if one of the new group names is now the widest group
- name in the full group list window. */
-
- SetPort(gFullGroupWindow);
- if (gPrefs.maxGroupNameWidth > 0) {
- for (i = 0; i < numNew; i++) {
- x = &(*groupArray)[i];
- strcpy(groupName, *gGroupNames + x->nameOffset);
- nameWidth = TextWidth(groupName, 0, strlen(groupName));
- if (nameWidth > gPrefs.maxGroupNameWidth) gPrefs.maxGroupNameWidth = nameWidth;
- }
- }
-
- /* Add each new group name to the unsubscribed list of each open user group
- list window. */
-
- wind = FrontWindow();
- while (wind != nil) {
- if (GetMyWindowKind(wind) == kGroup) {
- info = (TWindow**)GetWRefCon(wind);
- unsubscribed = (**info).unsubscribed;
- if (unsubscribed != nil) {
- for (i = 0; i < numNew; i++) {
- x = &(*groupArray)[i];
- strcpy(groupName, *gGroupNames + x->nameOffset);
- err = AddGroupToUnsubscribedList(groupName, unsubscribed);
- if (err != noErr) goto exit;
- }
- }
- }
- wind = (WindowPtr)((WindowPeek)wind)->nextWindow;
- }
-
- /* Return. */
-
- *newGroupsArray = groupArray;
- *numNewGroups = numNew;
- SetPort(port);
- return noErr;
-
- exit:
-
- MyDisposeHandle(strings);
- MyDisposeHandle(groupArray);
- MySetHandleSize(gGroupNames, savedGroupNamesSize);
- SetPort(port);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoCheckForNewGroups
-
- Handle the "Check for New Groups" command.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoCheckForNewGroups (void)
- {
- TGroup **groupArray;
- short numGroups;
- WindowPtr wind;
- OSErr err = noErr;
-
- err = CheckForNewGroups(&groupArray, &numGroups);
- if (err != noErr) return err;
- if (numGroups > 0) {
- return MakeNewGroupsWindow(groupArray, numGroups, &wind);
- } else {
- return noErr;
- }
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoCheckForDeletedGroups
-
- Handle the "Check for Deleted Groups" command.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoCheckForDeletedGroups (void)
- {
- Handle strings = nil;
- Handle deleted = nil;
- long deletedNext, deletedAllocated, offset;
- short index, len, nameWidth, numDel, numToMoveDown;
- long numGroups, i;
- TGroup *x, *prev, *cur, *curEnd;
- char *p;
- OSErr err = noErr;
- CStr255 groupName;
- GrafPtr port;
- Str255 title;
- WindowPtr wind;
-
- GetPort(&port);
-
- err = DisplayStatusMessageNumber(kStrCheckingDelStatusMsg);
- if (err != noErr) goto exit;
-
- /* Get a list of all group names from the server. */
-
- err = GetGroupNames(0, &strings, &numGroups);
- if (err != noErr) goto exit;
-
- /* Mark all the groups in the full group list with status = 'd'. Then walk
- the fresh full group list we just got from the server and mark all
- the groups which still exist with status = ' '. This leaves just the
- deleted groups marked with status = 'd'. */
-
- for (i = 0, x = *gFullGroupArray; i < gNumGroups; i++, x++) x->status = 'd';
-
- for (i = 0, offset = 0; i < numGroups; i++) {
- err = GiveTime(false);
- if (err != noErr) goto exit;
- p = *strings + offset;
- index = FindGroupIndex(p);
- if (index != -1) (*gFullGroupArray)[index].status = ' ';
- offset += strlen(p) + 1;
- }
- MyDisposeHandle(strings);
- strings = nil;
-
- /* Allocate a buffer to hold the names of the deleted groups for display
- to the user. */
-
- err = MyNewHandle(0, &deleted);
- if (err != noErr) goto exit;
- deletedNext = deletedAllocated = 0;
-
- /* Walk the full group list. Copy the names of the deleted groups to the
- buffer. Also check to see if the group with the widest name in the full
- group list window has been deleted. */
-
- SetPort(gFullGroupWindow);
- numDel = 0;
- for (i = 0; i < gNumGroups; i++) {
- x = &(*gFullGroupArray)[i];
- if (x->status == 'd') {
- err = GiveTime(false);
- if (err != noErr) goto exit;
- numDel++;
- strcpy(groupName, *gGroupNames + x->nameOffset);
- len = strlen(groupName);
- if (deletedNext + len + 1 > deletedAllocated) {
- deletedAllocated += 1000;
- err = MySetHandleSize(deleted, deletedAllocated);
- if (err != noErr) goto exit;
- }
- strcpy(*deleted + deletedNext, groupName);
- deletedNext += len+1;
- *(*deleted + deletedNext - 1) = CR;
- if (gPrefs.maxGroupNameWidth > 0) {
- nameWidth = TextWidth(groupName, 0, len);
- if (nameWidth >= gPrefs.maxGroupNameWidth) gPrefs.maxGroupNameWidth = 0;
- }
- }
- }
-
- /* If there aren't any deleted groups, issue a note message and return. */
-
- if (numDel == 0) {
- MyDisposeHandle(deleted);
- NoteMessageNumber(kStrNoDelGroups);
- return noErr;
- }
-
- MySetHandleSize(deleted, deletedNext);
-
- /* Remove the deleted groups from the full group list. */
-
- prev = *gFullGroupArray;
- cur = *gFullGroupArray;
- curEnd = *gFullGroupArray + gNumGroups;
- numDel = 0;
- while (cur < curEnd) {
- numToMoveDown = 0;
- while (cur < curEnd && cur->status != 'd') {
- cur++;
- numToMoveDown++;
- }
- if (numDel > 0 && numToMoveDown > 0)
- BlockMoveData(prev + numDel, prev, numToMoveDown*sizeof(TGroup));
- prev += numToMoveDown;
- numDel++;
- cur++;
- }
-
- /* Update the full group list window, display the deleted group names to the
- user in a text window, and return. */
-
- gNumGroups -= numDel;
- MySetHandleSize(gFullGroupArray, gNumGroups*sizeof(TGroup));
- err = UpdateFullGroupWindow();
- if (err != noErr) goto exit;
- GetPString(kStrDelGroupsWindTitle, title);
- err = MakeNewTextWindow(title, 0, nil, deleted, &wind);
- if (err != noErr) goto exit;
-
- MyDisposeHandle(deleted);
- SetPort(port);
- return noErr;
-
- exit:
-
- MyDisposeHandle(strings);
- MyDisposeHandle(deleted);
- SetPort(port);
- return err;
- }
-
-
-
- /*----------------------------------------------------------------------------
- MustCloseBeforeRebuildDialog
-
- Present the "must close windows before rebuilding full group list" dialog.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- static OSErr MustCloseBeforeRebuildDialog (void)
- {
- OSErr err = noErr;
- DialogPtr dlg = nil;
- short item;
-
- err = MyGetNewDialog(kMustCloseBeforeRebuildDlg, ok, cancel, &dlg);
- if (err != noErr) return err;
- SysBeep(0);
- MyModalDialog(dlg, gDialogFilterUPP, &item);
- err = DoClose(dlg);
- if (err != noErr) return err;
- if (item == cancel) return userCanceledErr;
- return noErr;
- }
-
-
-
- /*----------------------------------------------------------------------------
- DoRebuildFullGroupList
-
- Handle the "Rebuild Full Group List" command.
-
- Exit: function result = error code.
- ----------------------------------------------------------------------------*/
-
- OSErr DoRebuildFullGroupList (void)
- {
- TGroup **newFullGroupArray = nil;
- long newNumGroups;
- Handle newGroupNames = nil;
- TGroup *x;
- long i;
- char *p;
- OSErr err = noErr;
- WindowPtr wind;
- TWindowKind kind;
- Boolean promptBeforeClose = true;
-
- /* Close all group windows except for the full group list window, and close
- all subject windows. We must do this because group and subject window data
- structures contain offsets into the old group names gGroupNames, which is
- about to be blown away and replaced. */
-
- while (true) {
- wind = FrontWindow();
- while (wind != nil) {
- kind = GetMyWindowKind(wind);
- if ((kind == kGroup && wind != gFullGroupWindow) ||
- kind == kSubject) break;
- wind = (WindowPtr)((WindowPeek)wind)->nextWindow;
- }
- if (wind == nil) break;
- if (promptBeforeClose) {
- err = MustCloseBeforeRebuildDialog();
- if (err != noErr) goto exit;
- promptBeforeClose = false;
- }
- err = DoClose(wind);
- if (err != noErr) goto exit;
- }
-
- /* Display the status message. */
-
- err = DisplayStatusMessageNumber(kStrGetFullStatusMsg);
- if (err != noErr) goto exit;
-
- /* Get a list of all group names from the server. */
-
- err = GetGroupNames(0, &newGroupNames, &newNumGroups);
- if (err != noErr) goto exit;
-
- /* Check for too many groups. */
-
- if (newNumGroups > 16000) {
- newNumGroups = 16000;
- ErrorMessageNumber(kStrTooManyGroupsOnServer);
- }
-
- /* Allocate the new full group array. */
-
- err = MyNewHandle(newNumGroups * sizeof(TGroup), &newFullGroupArray);
- if (err != noErr) goto exit;
-
- /* Initialize the new full group array. */
-
- for (i = 0, x = *newFullGroupArray, p = *newGroupNames; i < newNumGroups; i++, x++) {
- InitializeGroupRecord(x, p - *newGroupNames);
- p += strlen(p) + 1;
- }
- MySetHandleSize(newGroupNames, p - *newGroupNames);
-
- /* Sort the new full group array. */
-
- err = SortFullGroupArray(newFullGroupArray, newNumGroups, newGroupNames);
- if (err != noErr) goto exit;
-
- /* Make the new full group array and group names the real ones. Dispose the old
- ones. */
-
- MyDisposeHandle(gFullGroupArray);
- gFullGroupArray = newFullGroupArray;
- newFullGroupArray = nil;
- gNumGroups = newNumGroups;
- MyDisposeHandle(gGroupNames);
- gGroupNames = newGroupNames;
- newGroupNames = nil;
-
- /* Update the full group list window and return. */
-
- gPrefs.maxGroupNameWidth = 0;
- err = UpdateFullGroupWindow();
- if (err != noErr) goto exit;
- GetDateTime(&gPrefs.groupCheckTime);
- return noErr;
-
- exit:
-
- MyDisposeHandle(newFullGroupArray);
- MyDisposeHandle(newGroupNames);
- return err;
- }
-